package com.chenziwen.scala.chapter05

import com.chenziwen.scala

object Scala01_Class {
  def main(args: Array[String]): Unit = {

    // 创建Scala内部成员类对象
    val outer1 = new ScalaOuterClass()
    val outer2 = new ScalaOuterClass()

    // Scala创建内部类的方式和Java不太一样，Scala中将new关键字放在前，使用   对象.内部类   的方式创建
    val inner1 = new outer1.ScalaInnerClass()
    val inner2 = new outer2.ScalaInnerClass()

    // 注：Java中的内部类从属于外部类。Scala中的内部类从属于实例
    // Scala中内部类从属于外部类对象，所以外部类对象不一样，创建出来的内部类对象也不一样，无法互换使用，解决方法如下：testWithOutType的声明方式
    inner1.testWithType(inner1)
    inner2.testWithType(inner2)

    // 解决方法
    inner1.testWithOutType(inner2)
    inner2.testWithOutType(inner1)

    inner1.visitOuterClassProperty()
    inner2.visitOuterClassProperty()

    inner1.visitOuterClassPropertyWithAlias()
    inner2.visitOuterClassPropertyWithAlias()


    // 创建Scala内部静态类对象（其实是用过伴生类对象创建的）
    val staticInner = new scala.chapter05.ScalaOuterClass.StaticScalaInnerClass
    println(staticInner)

  }
}


class ScalaOuterClass {

  outer =>

  val name = "zhangsan"
  val sex = 20


  class ScalaInnerClass {

    // Scala中如果想在内部类中访问外部类的属性，有两种方式
    // 1.使用【外部类.this.属性名】的方式访问
    def visitOuterClassProperty(): Unit = {
      println("name = " + ScalaOuterClass.this.name)
    }

    // 2.使用给外部类定别名的形式【outer =>】，然后通过【outer.属性名】的方式访问。注：这种方式下，属性名必须定义在外部类对象别名的下方
    def visitOuterClassPropertyWithAlias(): Unit = {
      println("sex = " + outer.sex)
    }

    def testWithType(ic: ScalaInnerClass): Unit = {
      println(ic)
    }

    // 在方法声明上，如果使用【外部类#内部类】的方式，表示忽略内部类的对象关系，等同于Java中内部类的语法操作
    // 我们将这种方式称之为【类型投影】，忽略对象的创建方式，只考虑类型
    def testWithOutType(ic: ScalaOuterClass#ScalaInnerClass): Unit = {
      println(ic)
    }
  }

}

object ScalaOuterClass {

  class StaticScalaInnerClass {

  }

}
